package gobelinmaker.client;

import com.esotericsoftware.kryonet.Client;
import com.esotericsoftware.kryonet.Connection;
import com.esotericsoftware.kryonet.Listener;
import gobelinmaker.data.Kanava;
import gobelinmaker.server.ConnectionRequest;
import gobelinmaker.server.ConnectionResponse;
import gobelinmaker.server.DiscoveryRequest;
import gobelinmaker.server.DiscoveryResponse;
import gobelinmaker.server.GobelinServer;
import gobelinmaker.server.Network;
import gobelinmaker.server.ServerData;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.basic.BasicTabbedPaneUI;

/**
 * Alkalmazás főablaka.
 *
 * @author imruf84
 */
public class GobelinClientGUI extends javax.swing.JFrame {

    /**
     * Névtelen fülek neveinek számlálója.
     */
    private int unnamedTabsCounter = 1;
    /**
     * Görgetés sebessége.
     */
    public static int WHEEL_SCROLL_SIZE = 10;
    /**
     * Teljes képernyő.
     */
    private boolean fullscreen = false;
    /**
     * Teljes képernyő előtti állapot.
     */
    private Rectangle prevBounds = new Rectangle();

    /**
     * Creates new form MaindexnFrame
     */
    public GobelinClientGUI() {
        initComponents();
        updateMenuItems();
    }

    /**
     * Új kanava tároló hozzáadása.
     *
     * @param rows sorok száma
     * @param columns oszlopok száma
     * @param fileName file név, vagy null
     */
    public void appendNewKanavaPanel(final int rows, final int columns, final String fileName) {

        final AtomicBoolean b = new AtomicBoolean(true);

        JPanel lp = new JPanel(new BorderLayout());
        final JProgressBar pb = new JProgressBar(0, 0, 100);
        pb.setStringPainted(true);
        final JLabel l = new JLabel();
        lp.add(l, BorderLayout.WEST);
        lp.add(pb, BorderLayout.CENTER);
        final JButton cancelButton = new JButton("Mégsem");
        cancelButton.addActionListener(
                new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent ae) {
                        b.set(false);
                    }
                });
        lp.add(cancelButton, BorderLayout.EAST);
        final JPanel loadingPanel = new JPanel(new BorderLayout());
        loadingPanel.setBorder(BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.LOWERED));
        loadingPanel.add(lp, BorderLayout.SOUTH);

        this.mainTabbedPane.addTab("Névtelen " + this.unnamedTabsCounter, loadingPanel);
        this.mainTabbedPane.setSelectedIndex(this.mainTabbedPane.indexOfComponent(loadingPanel));

        updateMenuItems();

        final Component c = this;

        // Kanava létrehozása.
        new Thread() {
            @Override
            public void run() {
                cancelButton.requestFocus();
                boolean fileNameIsNull = (null == fileName);
                Kanava kanava = new Kanava(rows, columns, fileNameIsNull) {
                    @Override
                    public boolean updateCreation(int all, int created) {
                        if (l.getText().isEmpty()) {
                            l.setText(this.getColumnsCount() + "x" + this.getRowsCount() + " méretű kanava létrehozása: ");
                        }
                        pb.setValue(Math.round((float) created / (float) all * 50));
                        return b.get();
                    }
                };

                // Ha adtunk meg file nevet, akkor beolvassuk a tartalmát.
                boolean opened = false;
                if (!fileNameIsNull) {
                    try {
                        kanava.open(fileName);
                        opened = true;
                    } catch (FileNotFoundException ex) {
                        Dialogs.showOpenFailedMessageDialog(c, ex.getLocalizedMessage());
                    } catch (IOException ex) {
                        Dialogs.showOpenFailedMessageDialog(c, ex.getLocalizedMessage());
                    }
                }

                KanavaPanel kp = new KanavaPanel(kanava, true) {
                    @Override
                    public boolean updateCreation(int all, int created) {
                        pb.setValue(50 + Math.round((float) created / (float) all * 50));
                        return b.get();
                    }
                };

                //Ha mi szakítottuk meg a folyamatot, akkor töröljük a már létrehozott dolgokat.
                int index = mainTabbedPane.indexOfComponent(loadingPanel);
                if (!b.get()) {
                    mainTabbedPane.remove(index);
                    return;
                }

                // Egyébként létrehozzuk a maradék dolgokat is.
                mainTabbedPane.setComponentAt(index, kp);
                mainTabbedPane.setTabComponentAt(index, new ButtonTabComponent(mainTabbedPane));
                updateTabName(index);

                // Nem újonnan létrehozott kanava esetén elvégzünk pár műveletet.
                if (opened) {

                    // Szkript forráskódjának a másolása.
                    kp.setScriptSourceCode(kanava.getScriptSourceCode());

                    // A kanava alapból nem módosított.
                    kanava.setModified(false);
                }

                ButtonTabComponent btc = (ButtonTabComponent) mainTabbedPane.getTabComponentAt(index);
                btc.getCloseButton().addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        ButtonTabComponent btc = ((ButtonTabComponent) ((JButton) e.getSource()).getParent());
                        int index = btc.getTabbedPane().indexOfTabComponent(btc);
                        closeTab(index);
                    }
                });

                updateMenuItems();

            }
        }.start();

        this.unnamedTabsCounter++;
    }

    /**
     * Szerver panel hozzáadása.
     *
     * @param sd server adatai
     */
    public void appendNewServerPanel(ServerData sd) {
        final ServerPanel serverPanel = new ServerPanel(sd);
        this.mainTabbedPane.addTab(sd.toString(), serverPanel);

        int index = this.mainTabbedPane.indexOfComponent(serverPanel);
        this.mainTabbedPane.setSelectedIndex(index);

        mainTabbedPane.setComponentAt(index, serverPanel);
        mainTabbedPane.setTabComponentAt(index, new ButtonTabComponent(mainTabbedPane));

        ButtonTabComponent btc = (ButtonTabComponent) mainTabbedPane.getTabComponentAt(index);
        btc.getCloseButton().addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                ButtonTabComponent btc = ((ButtonTabComponent) ((JButton) e.getSource()).getParent());
                int index = btc.getTabbedPane().indexOfTabComponent(btc);
                closeTab(index);
            }
        });
    }

    /**
     * Kanava lekérdezése fül sorszáma alapján.
     *
     * @param index fül sorszáma
     * @return adott sorszámú fülhöz tartozó kanava
     */
    public Kanava getKanavaByTabIndex(int index) {

        KanavaPanel kp = this.getKanavaPanelByTabIndex(index);

        if (null == kp) {
            return null;
        }

        return kp.getKanava();
    }

    /**
     * Kanavapanel lekérdezése.
     *
     * @param index fül sorszáma
     * @return adott sorszámú fülhöz tartozó kanavapanel
     */
    public KanavaPanel getKanavaPanelByTabIndex(int index) {
        if (0 > index) {
            return null;
        }
        return ((KanavaPanel) this.mainTabbedPane.getComponentAt(index));
    }

    /**
     * Lapfül objektum lekérdezése sorszám alapján.
     *
     * @param index lap sorszáma
     * @return lap objektum
     */
    public ButtonTabComponent getButtonTabComponentByTabIndex(int index) {
        if (0 > index) {
            return null;
        }
        ButtonTabComponent btc = (ButtonTabComponent) this.mainTabbedPane.getTabComponentAt(index);
        return btc;
    }

    /**
     * Fül bezárása.
     *
     * @param index fül sorszáma
     * @return mentéssel kapcsolatos választás értéke
     */
    public int closeTab(int index) {

        Component tab = this.mainTabbedPane.getComponentAt(index);
        // Kanava esetén feldolgozzuk azt.
        if (tab instanceof KanavaPanel) {

            // Ha mentés szükséges, akkor rákérdezünk.
            KanavaPanel kp = this.getKanavaPanelByTabIndex(index);
            if (null == kp) {
                return JOptionPane.YES_OPTION;
            }

            Kanava kanava = kp.getKanava();
            if (kanava.saveNeeded()) {
                Object[] o = {"Igen", "Nem", "Mégsem"};
                int n = JOptionPane.showOptionDialog(
                        this,
                        "'" + this.mainTabbedPane.getTitleAt(index) + "' tartalma megváltozott."
                        + System.getProperty("line.separator")
                        + "Kívánja menteni a változásokat?",
                        "Mentés",
                        JOptionPane.YES_NO_CANCEL_OPTION,
                        JOptionPane.QUESTION_MESSAGE,
                        null, o, o[0]);

                if (JOptionPane.CANCEL_OPTION == n) {
                    return n;
                }
                if (JOptionPane.YES_OPTION == n) {
                    // Mentés elvégzése.
                    int a = this.saveKanava(index);
                    if (a == JOptionPane.NO_OPTION) {
                        return a;
                    }
                }

            }

            this.mainTabbedPane.remove(index);
            kp.closeCodeEditorWindow();
            return JOptionPane.YES_OPTION;

        }

        // Szerver panelt azonnal bezárunk.
        if (tab instanceof ServerPanel) {
            // Kapcsolat bontása.
            ServerPanel sp = (ServerPanel) this.mainTabbedPane.getComponentAt(index);
            sp.disconnect();

            // Fül eltávolítása.
            this.mainTabbedPane.remove(index);
            sp.closeDiscoveredHolesWindow();
            return JOptionPane.YES_OPTION;
        }

        // Egyébként nem zárunk be semmit.
        JOptionPane.showMessageDialog(
                this,
                "Nem zárhatja be az ablakot, amíg vannak futó alkalmazások!",
                "Ablak bezárása",
                JOptionPane.WARNING_MESSAGE);

        return JOptionPane.CANCEL_OPTION;
    }

    /**
     * Minden fül bezárása.
     *
     * @return mentéssel kapcsolatos választási érték
     */
    public int closeAllTabs() {
        while (0 < this.mainTabbedPane.getTabCount()) {
            if (JOptionPane.CANCEL_OPTION == this.closeTab(0)) {
                return JOptionPane.CANCEL_OPTION;
            }
        }

        return JOptionPane.YES_OPTION;
    }

    /**
     * Lapfül címének a frissítése.
     *
     * @param index lapfül sorszáma
     */
    public void updateTabName(int index) {

        KanavaPanel kp = this.getKanavaPanelByTabIndex(index);
        Kanava kanava = kp.getKanava();

        if (kanava.getFileSimpleName().isEmpty()) {
            return;
        }

        ButtonTabComponent btc = (ButtonTabComponent) this.mainTabbedPane.getTabComponentAt(index);
        btc.getTitleLabel().setText(kanava.getFileSimpleName());

        kp.updateCodeEditorWindow();
    }

    /**
     * Kanava mentése megadott néven.
     *
     * @param index lap sorszáma
     * @return a dialógus ablak visszatérési értéke
     */
    public int saveAsKanava(int index) {

        KanavaPanel kp = this.getKanavaPanelByTabIndex(index);
        Kanava kanava = kp.getKanava();

        JFileChooserOverwriteDialog fc = new JFileChooserOverwriteDialog();
        fc.addChoosableFileFilter(new UncopressedFileFilter());
        fc.setFileFilter(new CopressedFileFilter());
        fc.setAcceptAllFileFilterUsed(false);

        final Component c = this;

        int m = fc.showSaveDialog(this);
        if (m == JFileChooser.APPROVE_OPTION) {
            try {
                ExtensionFileFilter filter = (ExtensionFileFilter) fc.getFileFilter();
                File f = fc.getSelectedFile();
                String fileName = f.getAbsolutePath();
                if (!filter.accept(f)) {
                    fileName += filter.getUsableExtension();
                }
                kanava.saveAs(fileName, kp.getScriptSourceCode());
                this.updateTabName(index);
            } catch (IOException ex) {
                Dialogs.showSaveFailedMessageDialog(c, ex.getLocalizedMessage());
                return JOptionPane.NO_OPTION;
            }
        }

        return m;
    }

    /**
     * Kanava mentése.
     *
     * @param index fül indexe
     * @return a dialógus ablak visszatérési értéke
     */
    public int saveKanava(int index) {

        int m;
        final Component c = this;

        try {
            KanavaPanel kp = this.getKanavaPanelByTabIndex(index);
            Kanava kanava = kp.getKanava();

            // Mentés elvégzése.
            if (!kanava.save(kp.getScriptSourceCode())) {
                // Ha nincs megadva fájlnév akkor bekérjük és mentünk.
                m = this.saveAsKanava(index);
            } else {
                this.updateTabName(index);
                m = JOptionPane.YES_OPTION;
            }

        } catch (IOException ex) {
            Dialogs.showSaveFailedMessageDialog(c, ex.getLocalizedMessage());
            return JOptionPane.NO_OPTION;
        }

        return m;
    }

    /**
     * Kanava megnyitása.
     */
    public void openKanava() {
        JFileChooser fc = new JFileChooser();
        fc.addChoosableFileFilter(new UncopressedFileFilter());
        fc.setFileFilter(new CopressedFileFilter());
        fc.setAcceptAllFileFilterUsed(false);

        int m = fc.showOpenDialog(this);
        if (m == JFileChooser.APPROVE_OPTION) {
            String fileName = fc.getSelectedFile().getAbsolutePath();
            this.appendNewKanavaPanel(0, 0, fileName);
        }
    }

    /**
     * Thindexs method indexs called from windexthindexn the constructor to
     * indexnindextindexalindexze the form. WARNING: Do NOT modindexfy thindexs
     * code. The content of thindexs method indexs always regenerated by the
     * Form Edindextor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        mainTabbedPane = new javax.swing.JTabbedPane();
        this.mainTabbedPane.setUI(new BasicTabbedPaneUI() {
            private final Insets borderInsets = new Insets(0, 0, 0, 0);
            @Override
            protected void paintContentBorder(Graphics g, int tabPlacement, int selectedIndex) {
            }
            @Override
            protected Insets getContentBorderInsets(int tabPlacement) {
                return borderInsets;
            }
            @Override
            protected void paintContentBorderTopEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) {
                super.paintContentBorderTopEdge(g, tabPlacement, -1, x, y, w, h);
            }
        });
        menuBar = new javax.swing.JMenuBar();
        fileMenu = new javax.swing.JMenu();
        newMenuItem = new javax.swing.JMenuItem();
        jSeparator2 = new javax.swing.JPopupMenu.Separator();
        openMenuItem = new javax.swing.JMenuItem();
        importMenuItem = new javax.swing.JMenuItem();
        jSeparator3 = new javax.swing.JPopupMenu.Separator();
        saveMenuItem = new javax.swing.JMenuItem();
        saveAsMenuItem = new javax.swing.JMenuItem();
        jSeparator4 = new javax.swing.JPopupMenu.Separator();
        closeMenuItem = new javax.swing.JMenuItem();
        closeAllMenuItem = new javax.swing.JMenuItem();
        jSeparator1 = new javax.swing.JPopupMenu.Separator();
        exitMenuItem = new javax.swing.JMenuItem();
        serverMenu = new javax.swing.JMenu();
        connectMenuItem = new javax.swing.JMenuItem();
        windowMenu = new javax.swing.JMenu();
        fullscreenMenuItem = new javax.swing.JMenuItem();

        setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
        setTitle("Gobelin készítő v0.1");
        setIconImage(Toolkit.getDefaultToolkit().getImage(getClass().getClassLoader().getResource("icons/MainFrameIcon.png")));
        setMinimumSize(new java.awt.Dimension(400, 400));
        setName("GobelinMainFrame"); // NOI18N
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                formWindowClosing(evt);
            }
        });

        mainTabbedPane.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                mainTabbedPaneStateChanged(evt);
            }
        });
        getContentPane().add(mainTabbedPane, java.awt.BorderLayout.CENTER);

        fileMenu.setMnemonic('f');
        fileMenu.setText("Fájl");

        newMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_N, java.awt.event.InputEvent.CTRL_MASK));
        newMenuItem.setText("Új");
        newMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                newMenuItemActionPerformed(evt);
            }
        });
        fileMenu.add(newMenuItem);
        fileMenu.add(jSeparator2);

        openMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, java.awt.event.InputEvent.CTRL_MASK));
        openMenuItem.setText("Megnyitás...");
        openMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                openMenuItemActionPerformed(evt);
            }
        });
        fileMenu.add(openMenuItem);

        importMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_I, java.awt.event.InputEvent.SHIFT_MASK | java.awt.event.InputEvent.CTRL_MASK));
        importMenuItem.setText("Importálás...");
        fileMenu.add(importMenuItem);
        fileMenu.add(jSeparator3);

        saveMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.event.InputEvent.CTRL_MASK));
        saveMenuItem.setText("Mentés...");
        saveMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                saveMenuItemActionPerformed(evt);
            }
        });
        fileMenu.add(saveMenuItem);

        saveAsMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.event.InputEvent.SHIFT_MASK | java.awt.event.InputEvent.CTRL_MASK));
        saveAsMenuItem.setText("Mentés másként...");
        saveAsMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                saveAsMenuItemActionPerformed(evt);
            }
        });
        fileMenu.add(saveAsMenuItem);
        fileMenu.add(jSeparator4);

        closeMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_C, java.awt.event.InputEvent.CTRL_MASK));
        closeMenuItem.setText("Bezárás...");
        closeMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                closeMenuItemActionPerformed(evt);
            }
        });
        fileMenu.add(closeMenuItem);

        closeAllMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_C, java.awt.event.InputEvent.SHIFT_MASK | java.awt.event.InputEvent.CTRL_MASK));
        closeAllMenuItem.setText("Összes bezárása...");
        closeAllMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                closeAllMenuItemActionPerformed(evt);
            }
        });
        fileMenu.add(closeAllMenuItem);
        fileMenu.add(jSeparator1);

        exitMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_Q, java.awt.event.InputEvent.CTRL_MASK));
        exitMenuItem.setText("Kilépés");
        exitMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                exitMenuItemActionPerformed(evt);
            }
        });
        fileMenu.add(exitMenuItem);

        menuBar.add(fileMenu);

        serverMenu.setMnemonic('s');
        serverMenu.setText("Szerver");

        connectMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_C, java.awt.event.InputEvent.ALT_MASK));
        connectMenuItem.setText("Csatlakozás...");
        connectMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                connectMenuItemActionPerformed(evt);
            }
        });
        serverMenu.add(connectMenuItem);

        menuBar.add(serverMenu);

        windowMenu.setMnemonic('a');
        windowMenu.setText("Ablak");

        fullscreenMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F, java.awt.event.InputEvent.SHIFT_MASK | java.awt.event.InputEvent.CTRL_MASK));
        fullscreenMenuItem.setText("Teljes képernyő/ablak váltás");
        fullscreenMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                fullscreenMenuItemActionPerformed(evt);
            }
        });
        windowMenu.add(fullscreenMenuItem);

        menuBar.add(windowMenu);

        setJMenuBar(menuBar);

        pack();
        setLocationRelativeTo(null);
    }// </editor-fold>//GEN-END:initComponents

    /**
     * Alkalmazás bezárása.
     */
    private void quit() {
        if (JOptionPane.CANCEL_OPTION == this.closeAllTabs()) {
            return;
        }

        System.exit(0);
    }

    /**
     * Léptető ha megkapja a fókuszt, akkor kijelöljük a szövegét.
     *
     * @param sp
     */
    public static void setSpinnerFocusableSelect(JSpinner sp) {
        JSpinner.DefaultEditor editor = (JSpinner.DefaultEditor) sp.getEditor();
        JTextField textField = editor.getTextField();

        textField.addFocusListener(new FocusAdapter() {
            @Override
            public void focusGained(final FocusEvent e) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        JTextField tf = (JTextField) e.getSource();
                        tf.selectAll();
                    }
                });
            }
        });

        sp.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(final ChangeEvent e) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        JSpinner s = (JSpinner) e.getSource();
                        JSpinner.DefaultEditor ed = (JSpinner.DefaultEditor) s.getEditor();
                        ed.getTextField().selectAll();
                    }
                });
            }
        });

    }

    /**
     * Teljes képernyős mód lekérdezése.
     *
     * @return teljes képernyős mód esetén igaz egyébként hamis
     */
    public boolean isFullscreen() {
        return this.fullscreen;
    }

    /**
     * Teljes képernyős módra váltás.
     *
     * @param fullscreen igaz esetén teljes képernyős mód lesz, egyébként
     * ablakos
     */
    public void setFullScreen(boolean fullscreen) {

        if (fullscreen == true) {
            this.prevBounds = this.getBounds();
            dispose();
            setUndecorated(true);
            setBounds(0, 0, getToolkit().getScreenSize().width, getToolkit().getScreenSize().height);
            setVisible(true);
            this.fullscreen = true;
        } else {
            setVisible(true);
            setBounds(this.prevBounds);
            dispose();
            setUndecorated(false);
            setVisible(true);
            this.fullscreen = false;
        }
    }

    /**
     * Komponens dialógusának a lekérdezése.
     *
     * @param c komponens
     * @return dialógus
     */
    private JOptionPane getOptionPane(Component c) {
        Component pane = c.getParent();
        while (!(pane instanceof JOptionPane)) {
            pane = pane.getParent();
        }

        return (JOptionPane) pane;
    }

    private void exitMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exitMenuItemActionPerformed
        quit();
    }//GEN-LAST:event_exitMenuItemActionPerformed

    private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing
        quit();
    }//GEN-LAST:event_formWindowClosing

    private void newMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newMenuItemActionPerformed
        // Kanava létrehozása.
        JPanel p = new JPanel(new GridLayout(0, 2));

        JSpinner widthField = new JSpinner(new SpinnerNumberModel(10, 1, 1000, 1));
        GobelinClientGUI.setSpinnerFocusableSelect(widthField);
        p.add(new JLabel("Szélesség:"));
        p.add(widthField);

        JSpinner heightField = new JSpinner(new SpinnerNumberModel(10, 1, 1000, 1));
        GobelinClientGUI.setSpinnerFocusableSelect(heightField);
        p.add(new JLabel("Magasság:"));
        p.add(heightField);

        Object[] o = {"Létrehoz", "Mégsem"};
        int n = JOptionPane.showOptionDialog(
                this,
                p,
                "Kanava létrehozása",
                JOptionPane.YES_NO_OPTION,
                JOptionPane.DEFAULT_OPTION,
                null, o, widthField);

        if (JOptionPane.YES_OPTION == n) {
            this.appendNewKanavaPanel(heightField.getValue().hashCode(), widthField.getValue().hashCode(), null);
        }
    }//GEN-LAST:event_newMenuItemActionPerformed

    private void saveMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveMenuItemActionPerformed
        int index = this.mainTabbedPane.getSelectedIndex();
        if (0 > index) {
            return;
        }

        this.saveKanava(index);
    }//GEN-LAST:event_saveMenuItemActionPerformed

    private void saveAsMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveAsMenuItemActionPerformed
        int index = this.mainTabbedPane.getSelectedIndex();
        if (0 > index) {
            return;
        }

        this.saveAsKanava(index);
    }//GEN-LAST:event_saveAsMenuItemActionPerformed

    private void closeAllMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeAllMenuItemActionPerformed
        this.closeAllTabs();
    }//GEN-LAST:event_closeAllMenuItemActionPerformed

    private void closeMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeMenuItemActionPerformed
        this.closeTab(this.mainTabbedPane.getSelectedIndex());
    }//GEN-LAST:event_closeMenuItemActionPerformed

    private void openMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openMenuItemActionPerformed
        this.openKanava();
    }//GEN-LAST:event_openMenuItemActionPerformed

    private void connectMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_connectMenuItemActionPerformed

        final Component c = this;

        // A csatlakozás gombot letiltjuk, míg a szerverek keresése folyik, ezért az ő dolgait külön kezeljük.
        final JButton okButton = new JButton("Csatlakozás");
        okButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                JOptionPane pane = getOptionPane((JComponent) e.getSource());
                pane.setValue(okButton);
            }
        });
        okButton.setEnabled(false);

        // Mégsem gomb.
        final JButton cancelButton = new JButton("Mégsem");
        cancelButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                JOptionPane pane = getOptionPane((JComponent) e.getSource());
                pane.setValue(cancelButton);
            }
        });

        // Alap tároló létrehozása.
        final JPanel p = new JPanel(new GridLayout(0, 1));

        // Szerverlista létrehozása.
        final JComboBox<ServerData> serversList = new JComboBox<>();
        p.add(new JLabel("Szerverek:"));
        serversList.setEnabled(false);
        p.add(serversList);

        final HashMap<String, ServerData> serversHM = new HashMap<>();

        final int port = GobelinServer.DEFAULT_PORT;

        new Thread(new Runnable() {
            @Override
            public void run() {
                final LinkedList<InetAddress> servers = new LinkedList<>(new Client().discoverHosts(port, 1000));

                // Ha nem találtunk szervereket, akkor jelezzük majd kilépünk.
                if (servers.isEmpty()) {

                    JOptionPane pane = getOptionPane(cancelButton);
                    pane.setValue(cancelButton);

                    JOptionPane.showMessageDialog(null,
                            "Nem található szerver a hálózaton.",
                            "Hiba",
                            JOptionPane.ERROR_MESSAGE);
                }

                final AtomicInteger counter = new AtomicInteger(servers.size());
                while (!servers.isEmpty()) {
                    try {
                        Client c = new Client();
                        c.addListener(new Listener() {
                            @Override
                            public void connected(Connection connection) {
                                connection.sendTCP(new DiscoveryRequest());
                            }

                            @Override
                            public void received(Connection connection, Object o) {
                                if (o instanceof DiscoveryResponse) {
                                    DiscoveryResponse drp = (DiscoveryResponse) o;

                                    if (drp.serverAddress.equals(connection.getRemoteAddressTCP().getAddress().getHostAddress())) {

                                        ServerData sd = new ServerData(connection.getRemoteAddressTCP().getAddress());
                                        sd.setServerName(drp.serverName);
                                        sd.setServerPort(drp.serverPort);
                                        serversHM.put(sd.toString(), sd);
                                        //serversList.addItem(sd);
                                        //System.out.println(connection.getRemoteAddressTCP().getAddress());
                                        connection.getEndPoint().close();
                                        connection.getEndPoint().stop();
                                    }

                                    // Ha mindennel végeztünk, akkor jöhet a szerver választása.
                                    if (!(0 < counter.decrementAndGet())) {
                                        for (ServerData sd : serversHM.values()) {
                                            serversList.addItem(sd);
                                        }
                                        serversList.setEnabled(true);
                                        okButton.setEnabled(true);
                                        serversList.requestFocus();
                                    }
                                }
                            }
                        });

                        Network.register(c);
                        c.start();
                        c.connect(5000, servers.pop().getHostAddress(), port, port);
                    } catch (IOException ex) {
                        Dialogs.showErrorMessageDialog(c, ex.getLocalizedMessage());
                    }

                }

            }
        }).start();

        // Dialógus megjelenítése.
        Object[] o = {okButton, cancelButton};
        int n = JOptionPane.showOptionDialog(
                this,
                p,
                "Csatlakozás szerverhez",
                JOptionPane.YES_NO_OPTION,
                JOptionPane.DEFAULT_OPTION,
                null, o, serversList);

        // Csatlakozás megkezdése.
        if (JOptionPane.YES_OPTION == n) {
            final ServerData sd = (ServerData) serversList.getSelectedItem();
            final InetAddress server = sd.getAddress();
            String ip = server.getHostAddress();
            System.out.println("Connecting to server... " + ip);
            final Client client = new Client();
            Network.register(client);
            client.start();
            try {
                client.addListener(new Listener() {
                    @Override
                    public void connected(Connection connection) {
                        System.out.println("Connection request sent...");
                        // Csatlakozási kérelem küldése.
                        connection.sendTCP(new ConnectionRequest());
                    }

                    @Override
                    public void received(Connection connection, Object o) {
                        // Sikeres csatlakozás.
                        if (o instanceof ConnectionResponse) {
                            System.out.println("Connected.");
                            sd.setConnection(connection);
                            appendNewServerPanel(sd);
                            client.removeListener(this);
                        }
                    }
                });
                client.connect(5000, ip, port, port);
            } catch (IOException ex) {
                JOptionPane.showMessageDialog(this, "Csatlakozás a szerverhez sikertelen.\n" + ex, "Csatlakozás hiba", JOptionPane.ERROR_MESSAGE);
            }
        }

    }//GEN-LAST:event_connectMenuItemActionPerformed

    /**
     * Menupontok frissítése.
     */
    private void updateMenuItems() {
        JPanel p = (JPanel) mainTabbedPane.getSelectedComponent();

        if (0 < mainTabbedPane.getTabCount()) {
            closeMenuItem.setEnabled(true);
            closeAllMenuItem.setEnabled(true);
        } else {
            closeMenuItem.setEnabled(false);
            closeAllMenuItem.setEnabled(false);
        }

        // Kanava.
        if (p instanceof KanavaPanel) {
            saveMenuItem.setEnabled(true);
            saveAsMenuItem.setEnabled(true);
            return;
        }

        // Szerver.
        if (p instanceof ServerPanel) {
            saveMenuItem.setEnabled(false);
            saveAsMenuItem.setEnabled(false);
            return;
        }

        // Egyébként tiltjuk.
        saveMenuItem.setEnabled(false);
        saveAsMenuItem.setEnabled(false);

    }

    private void mainTabbedPaneStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_mainTabbedPaneStateChanged
        updateMenuItems();
    }//GEN-LAST:event_mainTabbedPaneStateChanged

    private void fullscreenMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fullscreenMenuItemActionPerformed
        this.setFullScreen(!this.isFullscreen());
    }//GEN-LAST:event_fullscreenMenuItemActionPerformed

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JMenuItem closeAllMenuItem;
    private javax.swing.JMenuItem closeMenuItem;
    private javax.swing.JMenuItem connectMenuItem;
    private javax.swing.JMenuItem exitMenuItem;
    private javax.swing.JMenu fileMenu;
    private javax.swing.JMenuItem fullscreenMenuItem;
    private javax.swing.JMenuItem importMenuItem;
    private javax.swing.JPopupMenu.Separator jSeparator1;
    private javax.swing.JPopupMenu.Separator jSeparator2;
    private javax.swing.JPopupMenu.Separator jSeparator3;
    private javax.swing.JPopupMenu.Separator jSeparator4;
    private javax.swing.JTabbedPane mainTabbedPane;
    private javax.swing.JMenuBar menuBar;
    private javax.swing.JMenuItem newMenuItem;
    private javax.swing.JMenuItem openMenuItem;
    private javax.swing.JMenuItem saveAsMenuItem;
    private javax.swing.JMenuItem saveMenuItem;
    private javax.swing.JMenu serverMenu;
    private javax.swing.JMenu windowMenu;
    // End of variables declaration//GEN-END:variables
}
